package itb.fhv.sa.pipesfilters;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

public class DataSink extends Component implements Runnable {

	private Component m_neighbour;
	private boolean m_EOF;
	private boolean m_exit;

	public static final int STANDARD = 0;
	public static final int SINGLE_FILE = 1;
	public static final int PAGE_FILES = 2;

	private int m_output;
	private File m_outputFile;
	private int m_pageCount;
	private String m_fileName;
	private FileWriter m_fw;


	// for push pipeline
	public DataSink() {
		m_output = STANDARD;
		m_outputFile = null;
		m_pageCount = 0;
		m_fileName = null;
		m_EOF = false;
		m_exit = false;
	}


	// for pull pipeline
	public DataSink(Component previous) {
		m_output = STANDARD;
		m_outputFile = null;
		m_pageCount = 0;
		m_fileName = null;
		m_neighbour = previous;
		m_EOF = false;
		m_exit = false;
	}


	/**
	 * Reads the next element of data from the pipeline and writes it to the
	 * output.
	 * 
	 * @return The read data element.
	 */
	@Override
	public PLOutput read() {
		Page page = (Page) m_neighbour.read();

		if (page.getContent() != null) {

			while (!page.getContent().endsWith("\1")) {
				write(page);
				page = (Page) m_neighbour.read();
			}

			write(page);
		}

		return page;
	}


	/**
	 * Writes data to the specified output.
	 * 
	 * @param plo
	 *            The data to write.
	 * @return true, if the data was written, false otherwise.
	 */
	@Override
	public boolean write(PLOutput plo) {

		if (m_output == PAGE_FILES) {

			if (m_fileName == null) {
				// use a default file name
				m_fileName = new String("File_1");
			}

			m_pageCount++;

			// create output file for this page using page number
			String outFile = new String(m_fileName + "_page_"
					+ String.valueOf(m_pageCount) + ".txt");
			m_outputFile = new File(outFile);

			if (!m_outputFile.exists()) {

				try {
					m_outputFile.createNewFile();
				} catch (IOException e) {
					System.out.println("Could not create " + outFile);
					e.printStackTrace();
				}

			}

			try { // create a file writer and write data
				m_fw = new FileWriter(m_outputFile);
				m_fw.write(((Page) plo).getContent());
				m_fw.write("\r\n");
				m_fw.flush();
				m_fw.close();
			} catch (IOException e) {
				System.out.println("Could not write to " + outFile);
				e.printStackTrace();
			}

		} else if (m_output == SINGLE_FILE) {

			if (m_fileName == null) {
				m_fileName = new String("File_1");
			}

			// create the file using fileName attribute
			m_outputFile = new File(m_fileName + "_new" + ".txt");

			if (!m_outputFile.exists()) {

				try {
					m_outputFile.createNewFile();
				} catch (IOException e) {
					System.out.println("Could not create " + m_fileName);
					e.printStackTrace();
				}

			}

			if (m_fw == null) {
				// make sure that the output stream exists
				try {
					m_fw = new FileWriter(m_outputFile);
				} catch (IOException e) {
					System.out.println("Could not write to " + m_fileName);
					e.printStackTrace();
				}

			}

			try { // write to the file
				m_fw.write(((Page) plo).getContent());
				m_fw.write("\r\n");
				m_fw.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}

		} else {
			// standard output to console
			System.out.println(((Page) plo).getContent());
			System.out
					.println("************************************************************\n");
		}

		return false;
	}


	public int getOutput() {
		return m_output;
	}


	/**
	 * Sets the output of the data.
	 * 
	 * @param output
	 *            Determines, what should happen with the data: STANDARD: the
	 *            data is printed to the console. SINGLE_FILE: the data is
	 *            printed into a single file. PAGE_FILES: each page is printed
	 *            to a seperate file.
	 */
	public void setOutput(int output) {
		m_output = output;
	}


	/**
	 * Sets the fileName attribute. This is used to name the output files.
	 * 
	 * @param fileName
	 *            The name to be used for the output files.
	 */
	public void setFileName(String fileName) {
		m_fileName = new String(fileName);
	}


	@Override
	public void flush() {
		// empty for now //
	}


	/**
	 * Reads the next page from the pipeline and writes it to the specified
	 * output.
	 */
	private void readPage() {
		Page page = (Page) m_neighbour.read();

		if (page != null) {

			// detect the last page
			if (page.getContent().contains("\1")) {
				
				if (m_exit == false) {
					write(page);
					System.out.println("\nTHIS IS THE LAST PAGE");
				}
				
				m_EOF = true;
			} else {
				
				if (m_exit == false) {
					write(page);
				}
				
			}

		} else {
			System.out.println("not ready");
		}

	}


	/**
	 * Enables user to interactively pull pages from the pipeline. If input is
	 * 'y', the next page will be pulled, if input is 'n', the application will
	 * exit.
	 */
	public void run() {
		char command = 0;
		BufferedInputStream in = new BufferedInputStream(System.in);

		while (m_EOF == false) {
			System.out.println("Get next page (y / n)?");

			 try {
			 command = (char) in.read();
			 } catch (IOException e1) {
			 e1.printStackTrace();
			 }
			
			 if (command == 'y') {
			 readPage();
			 } else if (command == 'n') {
				 m_exit = true;
				 
				 // read until the end, so that all thread terminate
				 while (m_EOF == false) {
					 readPage();
				 }
			 
			 System.out.println("EXITING PROGRAM");
			 }

		}

	}

}
